#ifndef RTSPSTREAMCLIENT_H
#define RTSPSTREAMCLIENT_H

#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <time.h>
#include <pthread.h>
#include <list>

//#define USE_DECODERS

#include "QOSMeasurementRecord.h"
#ifdef USE_DECODERS
#include "DecoderClientThread.h"
#endif

#include "liveMedia.hh"
#include "BasicUsageEnvironment.hh"
#include "GroupsockHelper.hh"

#include "MRSink.h"
#include "MR264Sink.h"

using namespace std;

class RTSPStreamClient;

struct afterPlayingArgs
{
	RTSPStreamClient* client;
	MediaSubsession* subsession;
};

struct clientConfFileArgs
{
	bool audioOnly;
	bool videoOnly;
	string singleMedium;
	int verbosityLevel;
	double duration;
	double durationSlop;
	double initialSeekTime;
	double scale;
	unsigned int interPacketGapMaxTime;
	bool playContinuously;
	bool notifyOnPacketArrival;
	string username;
	string password;
	string proxyServerName;
	unsigned short proxyServerPortNum;
	unsigned short desiredPortNum;
	unsigned int fileSinkBufferSize;
	unsigned int socketInputBufferSize;
	unsigned int qosMeasurementIntervalMS;
	bool displayQOS;
};

class RTSPStreamClient
{
public:
	RTSPStreamClient(string pgName, string url, string confFile);
	~RTSPStreamClient();

	void readConfFile();
	void configureClient();

	void sendOptionRequest();
	void sendDescribeRequest();

	void createNewInputReceiver();
	void configureInputReceiver();
	void createNewOutputSink();

	void startPlaying();

	void sessionAfterPlayingInClass();
	void subsessionAfterPlayingInClass(MediaSubsession* subsession);

	void beginQOSMeasurment();
	void scheduleNextQOS();
	void periodicQOSMeasurementInClass();
	void printQOS();

	void checkForPacketArrivalInClass();
	void checkInterPacketGapsInClass();
	void sessionTimerHandlerInClass();
	void subsessionByeHandlerInClass(MediaSubsession* subsession);

	void shutdownClient(int code);

	void prepareClient();
	void playFromURL();


private:
	UsageEnvironment* env;
	TaskScheduler* scheduler;

	string urlToPlay;
	string progName;
	RTSPClient* rtspClient;
	bool okForDescribe;
	unsigned int statusCode;
	string sdpDescription;

	MediaSession* session;
	bool madeProgress;
	bool firstTime;

	string confFileName;
	ifstream confFile;
	clientConfFileArgs ccfa;
	struct timeval startTime;

	TaskToken sessionTimerTask;
	TaskToken arrivalCheckTimerTask;
	TaskToken interPacketGapCheckTimerTask;
	TaskToken qosMeasurementTimerTask;

	unsigned int nextQOSMeasurementUSecs;
	qosMeasurementRecord* qosRecordHead;
	MRSink *outputSink;
#ifdef USE_DECODERS
	list<DecoderClient*> listOfDecoder;
#endif
};


void subsessionAfterPlaying(void* clientData);
void subsessionByeHandler(void* clientData);
void sessionTimerHandler(void* clientData);
void checkForPacketArrival(void* clientData);
void checkInterPacketGaps(void* clientData);
void periodicQOSMeasurement(void* clientData);

extern unsigned int totNumPacketReceived;

#endif
